/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cc.lifepage.server.ai.controller;

import cc.lifepage.server.ai.web.input.PromptCommand;
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import com.alibaba.cloud.ai.dashscope.chat.MessageFormat;
import com.alibaba.cloud.ai.dashscope.common.DashScopeApiConstants;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.content.Media;
import org.springframework.util.MimeTypeUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.model.ChatModel;

import java.net.URI;
import java.util.List;

/**
 * @author yuluo
 * @author <a href="mailto:yuluo08290126@gmail.com">yuluo</a>
 */

@RestController
@RequestMapping("/v1/client")
@Slf4j
public class DashScopeChatClientController {

    private static final String DEFAULT_PROMPT =
            "你是一个职业的讣告撰写师，你是一个既能严谨写作，又能使用优美文笔的职业写手，你可以根据逝者的年龄的挑选合理的措辞。你会使用后面给出的模板，并为占位符填充数据，但是会修复填充数据后的文案，让其通顺。其中有些字段可能没有值，如果值则使用空字符填充，在调整通顺时，去掉无意义的空格。请以中文习惯和模板文风来表示时间、日期、年龄和称谓。最后以json的方式将整个模板分成顺序的4部分输出（4个字符串）,请不要带任何解释信息，纯json文本，不需要放在一个code块中。第一个是死亡的基础信息,key: base; 第二个是对死亡事件的描述或者对逝者的评价, key:desc; 第三个是举行仪式的信息, key:ceremony; 第四个是additionMsg所代表的补充信息, key: addition。 模板如下：```吾等沉痛宣告，{relation}{name}，{reason}，不幸于{deathTime}在{deathPlace}{deathWay}，{age}。{description}兹定于{ceremony.time}在{ceremony.location}，以表哀思，敬请各位亲朋好友莅临{ceremony.type}，共同缅怀逝者，寄托哀愁。{additionMsg}谨代表全家，叩首泣谢，期盼您的到来，共同送别{relation3rd}。```   填充数据如下\n" +
                    "```{\n" +
                    "  relation: \"父亲\",\n" +
                    "  name: \"宋宽柱\",\n" +
                    "  reason: \"\",\n" +
                    "  deathTime: \"2023-03-23 23:00\",\n" +
                    "  deathPlace: \"\",\n" +
                    "  deathWay: \"\",\n" +
                    "  age: \"78\",\n" +
                    "  description: \"父亲一生勤勉持家，品德高尚今骤离人世，举家悲痛，痛彻心扉。\",\n" +
                    "  ceremony.time: \"2025-01-13 11:00\",\n" +
                    "  ceremony.location: \"山东省青岛市黄岛区宝山镇金沟村\",\n" +
                    "  ceremony.type: \"追悼会\",\n" +
                    "  additionMsg: \"我们诚挚地邀请每一位关心、爱护父亲的朋友前来吊唁，以慰在天之灵。\",\n" +
                    "  relation3rd: \"\"\n" +
                    "}```";

    private final ChatClient dashScopeChatClient;

    public DashScopeChatClientController(ChatModel chatModel) {

        // 构造时，可以设置 ChatClient 的参数
        // {@link org.springframework.ai.chat.client.ChatClient};
        this.dashScopeChatClient = ChatClient.builder(chatModel)
                // 实现 Logger 的 Advisor
                .defaultAdvisors(
                        new SimpleLoggerAdvisor()
                )
                // 设置 ChatClient 中 ChatModel 的 Options 参数
                .defaultOptions(
                        DashScopeChatOptions.builder()
//								.withModel("qwen-3-235b-a22b")
                                .withTemperature(0.7)
                                .withMaxToken(4000)
                                .withTopP(0.5)
                                .build()
                )
                .build();
    }

    // 也可以使用如下的方式注入 ChatClient
    // public DashScopeChatClientController(ChatClient.Builder chatClientBuilder) {
    //
    //  	this.dashScopeChatClient = chatClientBuilder.build();
    // }


    @ResponseBody
    @PostMapping("/chat:byPrompt")
    public String chatByPrompt(@RequestBody @Validated PromptCommand command) {
        String result = dashScopeChatClient.prompt(command.getPrompt()).call().content();
        log.info("request: {} \n response:{}", command, result);
        return result.replaceAll("```json", "").replaceAll("```", "");
    }

    /**
     * ChatClient 简单调用
     */
    @GetMapping("/simple/chat")
    public String simpleChat() {
        return dashScopeChatClient.prompt(DEFAULT_PROMPT).call().content();
    }

    /**
     * ChatClient 流式调用
     */
    @GetMapping("/stream/chat")
    public Flux<String> streamChat(HttpServletResponse response) {

        response.setCharacterEncoding("UTF-8");
        return dashScopeChatClient.prompt(DEFAULT_PROMPT).stream().content();
    }


    /**
     * 图片分析接口 - 通过 URL
     */
    @GetMapping("/image/analyze/url")
    public String analyzeImageByUrl(@RequestParam(defaultValue = "请分析这张图片的内容") String prompt,
                                    @RequestParam String imageUrl) {
        try {
            // 创建包含图片的用户消息
            List<Media> mediaList = List.of(new Media(MimeTypeUtils.IMAGE_JPEG, new URI(imageUrl)));
            UserMessage message = UserMessage.builder()
                    .text(prompt)
                    .media(mediaList)
                    .build();

            // 设置消息格式为图片
            message.getMetadata().put(DashScopeApiConstants.MESSAGE_FORMAT, MessageFormat.IMAGE);

            // 创建提示词，启用多模态模型
            Prompt chatPrompt = new Prompt(message,
                    DashScopeChatOptions.builder()
                            .withModel("qwen-vl-max-latest")  // 使用视觉模型
                            .withMultiModel(true)             // 启用多模态
                            .withVlHighResolutionImages(true) // 启用高分辨率图片处理
                            .withTemperature(0.7)
                            .build());
            // 调用模型进行图片分析
            return dashScopeChatClient.prompt(chatPrompt).call().content();
        } catch (Exception e) {
            return "图片分析失败: " + e.getMessage();
        }
    }

    /**
     * 图片分析接口 - 通过文件上传
     */
    @PostMapping("/image/analyze/upload")
    public String analyzeImageByUpload(@RequestParam(defaultValue = "请分析这张图片的内容") String prompt,
                                       @RequestParam("file") MultipartFile file) {
        try {
            // 验证文件类型
            if (!file.getContentType().startsWith("image/")) {
                return "请上传图片文件";
            }

            // 创建包含图片的用户消息
            Media media = new Media(MimeTypeUtils.parseMimeType(file.getContentType()), file.getResource());
            UserMessage message = UserMessage.builder()
                    .text(prompt)
                    .media(media)
                    .build();

            // 设置消息格式为图片
            message.getMetadata().put(DashScopeApiConstants.MESSAGE_FORMAT, MessageFormat.IMAGE);

            // 创建提示词，启用多模态模型
            Prompt chatPrompt = new Prompt(message,
                    DashScopeChatOptions.builder()
                            .withModel("qwen-vl-max-latest")  // 使用视觉模型
                            .withMultiModel(true)             // 启用多模态
                            .withVlHighResolutionImages(true) // 启用高分辨率图片处理
                            .withTemperature(0.7)
                            .build());

            // 调用模型进行图片分析
            return dashScopeChatClient.prompt(chatPrompt).call().content();

        } catch (Exception e) {
            return "图片分析失败: " + e.getMessage();
        }
    }

}
